package vanillajdk8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class TestAMZ {

    public static void main(String... args) {
        Puzzle c = new Puzzle(); 
        String s = "NNSSSSNS";
        Puzzle.Status end = c.breathMove(s);
        System.out.println("Final label: " + end.status + " Moves: " + end.moves.size() + " the moves: " + Arrays.toString(end.moves.toArray()));
    }

    public static class Puzzle {

        /**
         * breath first moves.
         *
         * @param status
         * @return
         */
        public Status breathMove(String status) {
            if (done(status.toCharArray())) {
                return new Status(status, new ArrayList<Move>());
            }

            Queue<Status> sQueue = new LinkedList<Status>();
            sQueue.add(new Status(status, new ArrayList<Move>()));
            while (!sQueue.isEmpty()) {
                Status s = sQueue.remove();
                for (Move m : Move.values()) {
                    String newState = transform(s.status, m);
                    List<Move> moves = new ArrayList<Move>(s.moves);
                    moves.add(m);
                    Status newStatus = new Status(newState, moves);
                    if (done(newState.toCharArray())) {
                        return newStatus;
                    }
                    sQueue.add(newStatus);
                }
            }
            return null;
        }

        private String transform(String s, Move m) {
            int[] pos = m.getPositions();
            char[] status = s.toCharArray();
            for (int i : pos) {
                status[i] = transform(status[i]);
            }
            return String.valueOf(status);
        }

        private class Status {

            String status;
            List<Move> moves;

            Status(String s, List<Move> moves) {
                this.status = s;
                this.moves = moves;
            }
        }

        private char transform(char c) {
            switch (c) {
                case 'N':
                    return 'E';
                case 'E':
                    return 'S';
                case 'S':
                    return 'W';
                case 'W':
                    return 'N';
            }
            return c;
        }

        private boolean done(char[] status) {
            char c = status[0];
            for (int i = 1; i < status.length; i++) {
                if (c != status[i]) {
                    return false;
                }
            }
            return true;
        }

    }

    private enum Move {

        A(new int[]{0, 1}),
        B(new int[]{0, 1, 2}),
        C(new int[]{1, 4, 5, 6}),
        D(new int[]{2, 5}),
        E(new int[]{3, 5}),
        F(new int[]{3, 7}),
        G(new int[]{5, 7}),
        H(new int[]{6, 7});

        int[] positions;

        Move(int[] pos) {
            positions = pos;
        }

        public int[] getPositions() {
            return positions;
        }
    }
}
